#include "MCamera.h"


MCamera::MCamera(const MVertex &cp, const MVertex &la,const MVertex &up)
{
	setCamera(cp,la,up);
}

MCamera::~MCamera(void)
{
}

MCamera::MCamera(const MCamera &c) {
	camPos = c.camPos;
	lookAt = c.lookAt;
	upV = c.upV;
	rightV = (lookAt - camPos).CrossProduct(upV).normalize();
	topV = rightV.CrossProduct(lookAt - camPos).normalize();
}
void MCamera::setCamera(const MVertex &cp, const MVertex &la,const MVertex &up) {
	camPos = cp;
	lookAt = la;
	upV = up;
	rightV = (lookAt - camPos).CrossProduct(up).normalize();
	topV = rightV.CrossProduct(lookAt - camPos).normalize();
}

void MCamera::translate(const float &x, const float &y, const float &z) {
	camPos = camPos.translate(x,y,z);
	lookAt = lookAt.translate(x,y,z);
}

void MCamera::updateGluLookAt() {
	gluLookAt(camPos.point[0],camPos.point[1],camPos.point[2],
		lookAt.point[0],lookAt.point[1],lookAt.point[2],
		upV.point[0],upV.point[1],upV.point[2]);
}

void MCamera::rotate(float deg, int x, int y, int z) {
	float theta = deg/180*PI;
	if(x==1) {
		camPos = camPos.rotateX(theta);
		topV = topV.rotateX(theta);
	}
	if(y==1) {
		camPos = camPos.rotateY(theta);
		topV = topV.rotateY(theta);
	}
	if(z==1) {
		camPos = camPos.rotateZ(theta);
		topV = topV.rotateZ(theta);
	}
}

void MCamera::scale(float x, float y, float z) {
	camPos = camPos.scaling(x,y,z);
}

void MCamera::rotateAroundAxis(const MVertex &v1, const MVertex &v2, float deg) {
	float theta = deg/180*PI;
	MMatrix mT, mM, mR, mMb, mTb;
	//set translate matrix
	mT.setMatrix(1,0,0,-v1.point[0],0,1,0,-v1.point[1],0,0,1,-v1.point[2],0,0,0,1);
	//set translate back matrix
	mTb.setMatrix(1,0,0,v1.point[0],0,1,0,v1.point[1],0,0,1,v1.point[2],0,0,0,1);
	//get its own world axis
	MVertex u = getVertex(v1,v2).normalize(); //u match to +x
	MVertex n,v;
	if(isEqual(u.point[0],0) && isEqual(u.point[2],0)) {//if u is the same as up vector
		if(isEqual(u.point[1],1)) {
			n = MVertex(1,0,0);
			v = MVertex(0,0,1);
		}
		else if(isEqual(u.point[1],-1)) {
			n = MVertex(0,0,1);
			v = MVertex(1,0,0);
		}
		else {
			fprintf(stderr,"rotateAroundOwnAxis error\n");
		}
	}
	else {
		n = u.CrossProduct(MVertex(0,1,0)).normalize(); //n match to +z
		v = n.CrossProduct(u).normalize(); //v match to +y
	}
	//set rotation matrix turn vertex from own axis to world axis
	mM.setMatrix(u.point[0], u.point[1], u.point[2], 0,
		v.point[0], v.point[1], v.point[2], 0,
		n.point[0], n.point[1], n.point[2],0,
		0,0,0,1);
	//set rotation matrix turn vertex from world axis to its own world
	mMb.setMatrix(u.point[0], v.point[0], n.point[0], 0,
		u.point[1], v.point[1], n.point[1], 0,
		u.point[2], v.point[2], n.point[2], 0,
		0,0,0,1);
	//set rotation matrix rotate vertex around x axis which is the central axis
	mR.setMatrix(1,0,0,0,
		0,cos(theta),-sin(theta),0,
		0,sin(theta),cos(theta),0,
		0,0,0,1);

	//now, get the final magic matrix
	//matrix = mTb * mMb * mR * mM * mT
	MMatrix matrix = mTb.dotMatrix(mMb).dotMatrix(mR).dotMatrix(mM).dotMatrix(mT);
	camPos = matrix.dotVertex(camPos);
	lookAt = matrix.dotVertex(lookAt);
}


